package com.hg.miaosha.controller;

import cn.hutool.core.thread.ConcurrencyTester;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.RandomUtil;
import com.hg.miaosha.common.util.PageUtils;
import com.hg.miaosha.common.util.R;
import com.hg.miaosha.dto.PageDTO;
import com.hg.miaosha.service.SeckillService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


/**
 * created by skh on 2019/6/15
 */
@RestController
@Slf4j
@RequestMapping("/seckill")
@Api(tags = "秒杀相关接口")
public class SeckillController {

    @Autowired
    private SeckillService seckillService;

    @ApiOperation("获取秒杀商品列表")
    @GetMapping("/goods")
    public R getSeckillGoodsList(PageDTO pageDTO) {
        PageUtils pageUtils = seckillService.getSeckillGoodsList(pageDTO);
        return R.success(pageUtils);
    }

    @ApiOperation("开始秒杀一,最low的实现,会出现超卖")
    @PostMapping("/start")
    public R start(Integer seckillId) {
        seckillService.initData();

        ConcurrencyTester concurrencyTester = ThreadUtil.concurrencyTest(1000, new Runnable() {
            @Override
            public void run() {
                try {
                    seckillService.startSeckill(seckillId, getUserId());
                } catch (Exception e) {
                    log.error("秒杀异常:{}", e.getMessage());
                }
            }
        });

        Integer totalCount = seckillService.countSuccessSecKill();
        log.info("成功秒杀商品数量:{}", totalCount);
        log.info("总耗时:{}毫秒", concurrencyTester.getInterval());

        return R.success();
    }

    @ApiOperation("开始秒杀二,使用synchronized,不会出现超卖")
    @PostMapping("/startWithSynchronized")
    public R startWithSynchronized(Integer seckillId) {
        /*
        1000并发抢100个商品,耗时12000ms,不会超卖
         */
        seckillService.initData();

        ConcurrencyTester concurrencyTester = ThreadUtil.concurrencyTest(5000, new Runnable() {
            @Override
            public void run() {
                try {
                    seckillService.startWithSynchronized(seckillId, getUserId());
                } catch (Exception e) {
                    log.error("秒杀异常:{}", e.getMessage());
                }
            }
        });

        Integer totalCount = seckillService.countSuccessSecKill();
        log.info("成功秒杀商品数量:{}", totalCount);
        log.info("总耗时:{}毫秒", concurrencyTester.getInterval());

        return R.success();
    }
    @ApiOperation("开始秒杀三,使用lock,小概率出现超卖1个")
    @PostMapping("/startWithLock")
    public R startWithLock(Integer seckillId) {
        /*
        1000并发抢100个商品,耗时12000ms,小概率超卖1个
        5000并发抢1000个商品,耗时59082ms,小概率超卖1个
        超卖原因:锁释放了,但是事务还没有提交,导致下一个事务读取到了上个事务未提交的数据.
         */
        seckillService.initData();

        ConcurrencyTester concurrencyTester = ThreadUtil.concurrencyTest(5000, new Runnable() {
            @Override
            public void run() {
                try {
                    seckillService.startWithLock(seckillId, getUserId());
                } catch (Exception e) {
                    log.error("秒杀异常:{}", e.getMessage());
                }
            }
        });

        Integer totalCount = seckillService.countSuccessSecKill();
        log.info("成功秒杀商品数量:{}", totalCount);
        log.info("总耗时:{}毫秒", concurrencyTester.getInterval());

        return R.success();
    }

    @ApiOperation("开始秒杀四,使用aoplock,不会出现超卖")
    @PostMapping("/startWithAOPLock")
    public R startWithAOPLock(Integer seckillId) {
        /*
        5000并发抢1009个商品,耗时62353ms,不会出现超卖
         */
        seckillService.initData();

        ConcurrencyTester concurrencyTester = ThreadUtil.concurrencyTest(5000, new Runnable() {
            @Override
            public void run() {
                try {
                    seckillService.startWithAOPLock(seckillId, getUserId());
                } catch (Exception e) {
                    log.error("秒杀异常:{}", e.getMessage());
                }
            }
        });

        Integer totalCount = seckillService.countSuccessSecKill();
        log.info("成功秒杀商品数量:{}", totalCount);
        log.info("总耗时:{}毫秒", concurrencyTester.getInterval());

        return R.success();
    }

    @ApiOperation("开始秒杀五,使用数据库悲观锁,不会出现超卖")
    @PostMapping("/startWithPessimisticLock")
    public R startWithPessimisticLock(Integer seckillId) {
        /*
        5000并发抢1009个商品,耗时61365ms,不会出现超卖
         */
        seckillService.initData();

        ConcurrencyTester concurrencyTester = ThreadUtil.concurrencyTest(5000, new Runnable() {
            @Override
            public void run() {
                try {
                    seckillService.startWithPessimisticLock(seckillId, getUserId());
                } catch (Exception e) {
                    log.error("秒杀异常:{}", e.getMessage());
                }
            }
        });

        Integer totalCount = seckillService.countSuccessSecKill();
        log.info("成功秒杀商品数量:{}", totalCount);
        log.info("总耗时:{}毫秒", concurrencyTester.getInterval());

        return R.success();
    }


    @ApiOperation("开始秒杀六,使用数据库悲观锁,不会出现超卖")
    @PostMapping("/startWithPessimisticLock2")
    public R startWithPessimisticLock2(Integer seckillId) {
        /*
        5000并发抢1009个商品,耗时44411毫秒,不会出现超卖
         */
        seckillService.initData();

        ConcurrencyTester concurrencyTester = ThreadUtil.concurrencyTest(5000, new Runnable() {
            @Override
            public void run() {
                try {
                    seckillService.startWithPessimisticLock2(seckillId, getUserId());
                } catch (Exception e) {
                    log.error("秒杀异常:{}", e.getMessage());
                }
            }
        });

        Integer totalCount = seckillService.countSuccessSecKill();
        log.info("成功秒杀商品数量:{}", totalCount);
        log.info("总耗时:{}毫秒", concurrencyTester.getInterval());

        return R.success();
    }

    @ApiOperation("开始秒杀七,使用数据库乐观锁,不会出现超卖")
    @PostMapping("/startWithOptimisticLock")
    public R startWithOptimisticLock(Integer seckillId) {
        /*
        5000并发抢1009个商品,耗时44411毫秒,不会出现超卖
         */
        seckillService.initData();

        ConcurrencyTester concurrencyTester = ThreadUtil.concurrencyTest(5000, new Runnable() {
            @Override
            public void run() {
                try {
                    seckillService.startWithOptimisticLock(seckillId, getUserId());
                } catch (Exception e) {
                    log.error("秒杀异常:{}", e.getMessage());
                }
            }
        });

        Integer totalCount = seckillService.countSuccessSecKill();
        log.info("成功秒杀商品数量:{}", totalCount);
        log.info("总耗时:{}毫秒", concurrencyTester.getInterval());

        return R.success();
    }

    @ApiOperation("初始化秒杀数据")
    @PostMapping("/initData")
    public R initData() {
        seckillService.initData();
        return R.success();
    }

    @ApiOperation("测试限流")
    @GetMapping("/testRateLimit")
    public R testRateLimit() {
        seckillService.testRateLimit();
        return R.success();
    }


    private Integer getUserId() {
        //先随机产生一个用户id
        int userId = RandomUtil.randomInt(100000);
        return userId;
    }


}
